﻿
using System;
using System.Collections.Generic;
using System.Linq;
using DotNetNeural.Metrics;
namespace DotNetNeural.Utils.Adapters
{
    /// <summary>
    /// Provides extensions for metric
    /// </summary>
    public class MetricAdapter
    {
        /// <summary>
        /// Gets metric associated with given adapter
        /// </summary>
        public IMetric Metric { get; private set; }

        /// <summary>
        /// Creates new adapter using default euclid metric
        /// </summary>
        public MetricAdapter()
            : this(new DefaultMetric())
        {
        }

        /// <summary>
        /// Creates new adapter using given metric
        /// </summary>
        public MetricAdapter(IMetric metric)
        {
            if (metric == null)
                throw new NullReferenceException("Illegal null-reference metric");

            Metric = metric;
        }

        /// <summary>
        /// Calculates distance between two vectors with same dimensions
        /// </summary>
        public float CalculateDistance(float[] lhs, float[] rhs)
        {
            return Metric.CalculateDistance(lhs, rhs);
        }

        /// <summary>
        /// Calculates array of distances from given vector to collection of vectors
        /// </summary>
        public float[] CalculateDistance(float[] vec, IEnumerable<float[]> collection)
        {
            if (vec == null || collection == null)
                throw new NullReferenceException("Illegal null-reference arguments");

            List<float> result = new List<float>();

            foreach (var v in collection)
            {
                result.Add(CalculateDistance(vec, v));
            }

            return result.ToArray();
        }

        /// <summary>
        /// Calculates distances matrix
        /// </summary>
        public float[,] CalculateDistancesMatrix(IEnumerable<float[]> collection)
        {
            if (collection == null)
                throw new NullReferenceException("Illegal null-reference collection");

            int size = collection.Count();

            float[,] result = new float[size,size];

            int i = 0;
            foreach (var v1 in collection)
            {
                int j = 0;
                foreach (var v2 in collection)
                {
                    result[i, j] = CalculateDistance(v1, v2);
                    ++j;
                }
                ++i;
            }

            return result;
        }

        /// <summary>
        /// Gets value indicating whether given vector is closer then minDistance to any vector from collection
        /// </summary>
        public bool ExceedsMaxDistance(float[] vec, IEnumerable<float[]> collection, float minDistance)
        {
            if (vec == null || collection == null)
                throw new NullReferenceException("Illegal null-reference args");

            if (minDistance < 0)
                throw new ArgumentException("Illegal negative distance");

            foreach (var v in collection)
            {
                if (CalculateDistance(vec, v) > minDistance)
                    return true;
            }

            return false;
        }
    }
}
